#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# avatar_selector.py 
#
#  Copyright (c) 2006-2007 INdT (Instituto Nokia de Technologia)
#                2006-2007 Kenneth Rohde Christiansen
#
#  Author: Kenneth Rohde Christiansen <kenneth.christiansen@gmail.com>
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
#  USA

import pygtk
pygtk.require("2.0")
import gtk
import gobject
import os
import icon_theme
import shutil

class AvatarSelectorWindow(gobject.GObject):

    __gsignals__ = {
        'avatar-selected' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                (gobject.TYPE_PYOBJECT, )),
    }

    def __init__(self, account):
        gobject.GObject.__init__(self)

        self.my_id = account
        self.avatars = []

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_position(gtk.WIN_POS_CENTER)
        self.window.set_property("icon-name", 'ereseva')
        self.window.set_title("Choose a new avatar...")
        self.window.connect("delete-event", self.on_delete_event)

        self.window.set_resizable(False)

        user_dir = os.path.expanduser(os.environ.get("HOME")) 
        ereseva_dir = user_dir + "/.ereseva"
        self.avatar_dir = ereseva_dir + "/avatars"

        self.avatars_filename = self.avatar_dir + '/' + self.my_id + '.mru.txt'

        if not os.path.exists(ereseva_dir):
            os.mkdir(ereseva_dir)

        if not os.path.exists(self.avatar_dir):
            os.mkdir(self.avatar_dir)

        if not os.path.exists(self.avatars_filename):
            default_mru = "/usr/share/ereseva/default.mru.txt"

            if os.path.exists(default_mru):
                shutil.copy(default_mru, self.avatars_filename)

        self.avatar_store = gtk.ListStore(int, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, str)

        self.avatar_view = gtk.TreeView(self.avatar_store)
        self.avatar_view.set_headers_visible(False)
        self.avatar_view.set_size_request(200, 250)

        self.image_col = gtk.TreeViewColumn()

        self.render_pixbuf = gtk.CellRendererPixbuf()
        self.image_col.pack_start(self.render_pixbuf, False)
        self.image_col.set_attributes(self.render_pixbuf, pixbuf=1)
        self.avatar_view.append_column(self.image_col)

        self.filename_col = gtk.TreeViewColumn()

        self.render_text = gtk.CellRendererText()
        self.render_text.editable = False
        self.filename_col.pack_start(self.render_text, False)
        self.filename_col.set_attributes(self.render_text, text=3)
        self.avatar_view.append_column(self.filename_col)

        self.load_avatars()

        self.scrolled_win = gtk.ScrolledWindow()
        self.scrolled_win.set_border_width(6)
        self.scrolled_win.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrolled_win.set_shadow_type(gtk.SHADOW_ETCHED_IN)

        self.button_cancel = gtk.Button(stock=gtk.STOCK_CANCEL)

        self.button_apply = gtk.Button()#label="Options", stock="gtk-properties")
        hbox = gtk.HBox(spacing=2)
        ok_label = gtk.Label('Apply')
        ok_icon = gtk.image_new_from_stock(gtk.STOCK_OK, gtk.ICON_SIZE_BUTTON)
        hbox.pack_start(ok_icon)
        hbox.pack_start(ok_label)
        self.button_apply.add(hbox)
        
        self.button_add_avatar = gtk.Button (label="Browse...")
        self.button_remove_avatar = gtk.Button (label="Remove")

        self.show_checkbtn = gtk.CheckButton("Do not show avatar")
        self.show_checkbtn.set_border_width(6)

        self.help_label = gtk.Label("Choose an avatar to show to your contacts:")
        self.help_label.x_align = 0
        self.help_label.x_pad = 6
        self.preview_label = gtk.Label("Preview:")
        self.preview_label.x_align = 0
        self.preview_label.y_pad = 6

        self.avatar = gtk.Image()
        self.avatar.set_size_request(100, 100)
        self.avatar.set_from_pixbuf(icon_theme.icon_theme_get_default().\
            load_icon("avatar-unknown", 96, 0))

        self.main_vbox = gtk.VBox()
        self.main_vbox.set_border_width(6)

        self.center_hbox = gtk.HBox()

        self.right_vbox = gtk.VBox(False, 6)
        self.right_vbox.set_border_width(6)

        self.button_bar = gtk.HButtonBox()
        self.button_bar.set_border_width(6)
        self.button_bar.layout = gtk.BUTTONBOX_END
        self.button_bar.spacing = 6

        self.scrolled_win.add(self.avatar_view)

        self.main_vbox.pack_start(self.help_label, False, False, 6)
        self.main_vbox.pack_start(self.center_hbox, True, True, 0)
        self.main_vbox.pack_start(self.show_checkbtn, False, False, 0)
        self.main_vbox.pack_start(self.button_bar, False, False, 0)

        self.center_hbox.pack_start(self.scrolled_win, True, True, 0)
        self.center_hbox.pack_start(self.right_vbox, False, True, 0)

        self.right_vbox.pack_start(self.button_add_avatar, False, False, 0)
        self.right_vbox.pack_start(self.button_remove_avatar, False, False, 0)
        self.right_vbox.pack_start(self.preview_label, False, False, 0)
        self.right_vbox.pack_start(self.avatar, False, False, 0)

        self.button_bar.pack_start(self.button_cancel, False, False, 0)
        self.button_bar.pack_start(self.button_apply, False, False, 0)

        self.button_add_avatar.connect("clicked", \
                self.on_button_add_avatar_clicked)
        self.button_remove_avatar.connect("clicked", \
                self.on_button_remove_avatar_clicked)
        self.button_apply.connect("clicked", self.on_button_apply_clicked)
        self.button_cancel.connect("clicked", self.on_button_cancel_clicked)
        self.show_checkbtn.connect("clicked", self.on_checkbutton_clicked)
        self.avatar_view.get_selection().connect("changed", \
                self.on_avatar_activated)

        self.window.add(self.main_vbox)

        self.window.show_all()


    def on_button_apply_clicked(self, button):
        model, row_iter = self.avatar_view.get_selection().get_selected()

        extras = []

        # new pics got added!
        if len(self.avatars) > 0:
            extras = self.avatars
            self.avatars[:] = []

        if model.iter_is_valid(row_iter):
            filename = model.get_value(row_iter, 3)

        if os.path.exists(self.avatars_filename):

            avatars_file = open(self.avatars_filename, 'r')

            for line in avatars_file.readlines():
                picture = line.strip()

                if os.path.isfile(self.avatar_dir + "/" + picture):
                    self.avatars.append(picture)

            avatars_file.close()

        self.avatars + extras

        selected_picture = filename + ".png"
        selected_picture_path = self.avatar_dir + "/" + selected_picture

        try:
            index = self.avatars.index(selected_picture)
            self.avatars.pop(index)
        except ValueError, e:
            pass

        self.avatars.reverse()
        self.avatars.append(selected_picture)
        self.avatars.reverse()

        avatars_file = open(self.avatars_filename, 'w')

        for picture in self.avatars:
            avatars_file.write(picture + "\n")

        avatars_file.close()

        row_iter = self.avatar_store.append ()

        self.emit('avatar-selected', selected_picture_path)

        self.window.destroy()


    def on_button_cancel_clicked(self, button):
        self.emit('avatar-selected', None)
        self.window.destroy()


    def on_button_remove_avatar_clicked(self, button):
        model, row_iter = self.avatar_view.get_selection().get_selected()

        if not model.iter_is_valid(row_iter):
            return

        filename = model.get_value(row_iter, 3) + ".png"

        filepath = self.avatar_dir + "/" + filename

        if os.path.exists(filepath):
            os.remove(filepath)

        model.remove(row_iter)

        self.button_apply.set_property("sensitive", False)    


    def on_button_add_avatar_clicked(self, button):
        self.chooser = gtk.FileChooserDialog("Choose Avatar", None, \
                gtk.FILE_CHOOSER_ACTION_OPEN)

        self.chooser.set_current_folder(self.avatar_dir)

        filter = gtk.FileFilter()
        filter.add_pixbuf_formats()
        filter.set_name("Images")

        self.chooser.add_filter(filter)

        self.chooser.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.chooser.add_button (gtk.STOCK_OPEN, gtk.RESPONSE_OK)

        self.chooser.SelectMultiple = False
        self.chooser.DefaultResponse = gtk.RESPONSE_OK

        if self.chooser.run () == gtk.RESPONSE_OK:
            file_uri = self.chooser.get_uri()

            is_image = True

            try:
                file_path = file_uri[7:].replace('%20', ' ')

                pixbuf = gtk.gdk.pixbuf_new_from_file(file_path)

                pwidth = pixbuf.get_width()
                pheight = pixbuf.get_height()

                if pwidth < pheight:
                    width = 96.0
                    height = pheight * (width / pwidth)
                else:
                    height = 96.0
                    width = pwidth * (height / pheight)

                npixbuf = pixbuf.scale_simple (int(width), int(height), gtk.gdk.INTERP_BILINEAR)

                avatar_x = int(npixbuf.get_width() / 2) - 48
                avatar_y = int(npixbuf.get_height() / 2) - 48

                # cropping like MSN
                avatar = npixbuf.subpixbuf(avatar_x, avatar_y, 96, 96)

                thumbnail = avatar.scale_simple(32, 32, gtk.gdk.INTERP_BILINEAR)

            except Exception, e:
                is_image = False

            if is_image:
                filename = self.chooser.get_filename()
                filename = filename[(filename.rfind("/") + 1):]

                index = filename.rfind(".")

                if index > 0:
                    filename = filename[0:index]

                    count = 0

                    filepath = self.avatar_dir + "/" + filename + ".png"

                    if os.path.exists(filepath):
                        while os.path.exists(filepath):
                            count = count + 1
                            filepath = self.avatar_dir + "/" + filename + "-" + str(count) + ".png"

                    avatar.save(filepath, "png")

                if count != 0:
                    selected_picture = filename + "-" + str(count) + ".png"
                else:
                    selected_picture = filename + ".png"

                self.avatars.append(selected_picture)

                row_iter = self.avatar_store.append ()

                self.avatar_store.set_value(row_iter, 0, -1)
                self.avatar_store.set_value(row_iter, 1, thumbnail)
                self.avatar_store.set_value(row_iter, 2, avatar)
                self.avatar_store.set_value(row_iter, 3, filename)

                self.avatar_view.set_cursor(self.avatar_store.get_path(row_iter), \
                    self.avatar_view.get_column(1), False)

        self.chooser.destroy()


    def on_checkbutton_clicked(self, checkbutton):
        self.help_label.set_sensitive(not checkbutton.get_active())
        self.center_hbox.set_sensitive(not checkbutton.get_active())
        self.button_apply.set_sensitive(True)


    def on_avatar_activated(self, avatar):
        model, row_iter = self.avatar_view.get_selection().get_selected()

        if row_iter != None and model.iter_is_valid(row_iter):
            self.avatar.set_from_pixbuf(model.get_value(row_iter, 2))

        self.button_apply.set_property("sensitive", True)


    def load_avatars(self):
        def insert_file(filepath):
            index = filepath.rfind(".")

            count = 0

            if index > 0:
                filename = filepath[:index]

                avatar = gtk.gdk.pixbuf_new_from_file(self.avatar_dir + "/" + filepath)
                thumbnail = avatar.scale_simple(32, 32, gtk.gdk.INTERP_BILINEAR)

                row_iter = self.avatar_store.append()

                self.avatar_store.set_value(row_iter, 0, count)
                self.avatar_store.set_value(row_iter, 1, thumbnail)
                self.avatar_store.set_value(row_iter, 2, avatar)
                self.avatar_store.set_value(row_iter, 3, filename)

                count = count + 1

            self.avatar_store.set_sort_column_id(0, gtk.SORT_DESCENDING)

        if not os.path.exists(self.avatar_dir):
            return

        files = os.walk(self.avatar_dir).next()[2]

        avatar_files = {}

        for filepath in files:
            if not filepath.endswith("png"):
                continue

            avatar_files[filepath] = True

        if os.path.exists(self.avatars_filename):

            avatars_file = open(self.avatars_filename, 'r')

            for line in avatars_file.readlines():
                picture = line.strip()

                path = self.avatar_dir + "/" + picture
                if os.path.isfile(path):
                    try:
                        avatar_files.pop(picture)
                    except KeyError, e:
                        pass
                    insert_file(picture)

            avatars_file.close()

        for path in avatar_files:
            insert_file(path)


    def on_delete_event(self, widget, event=None, user_data=None):
        self.emit('avatar-selected', None)
        return False


    def present(self):
        self.window.present()


if __name__ == "__main__":
    window = AvatarSelectorWindow() 

    gtk.main()

